import bpy
from typing import Union
from os import listdir
from os.path import join
from ...addon.naming import FluidLabNaming
from ...libs.functions.basics import set_active_object
from ...libs.functions.modifiers import create_modifier
from ...libs.functions.get_common_vars import get_common_vars
from bpy.types import Operator, Object, VertexGroup, DynamicPaintCanvasSettings
from ...libs.functions.images import blur_image
from ...addon.paths import FluidLabPreferences


class FLUIDLAB_OT_dynamic_paint_add_brush(Operator):
    bl_idname = "fluidlab.dynamic_paint_add_brush"
    bl_label = "Add Brush"
    bl_description = "Add Brush"
    bl_options = {"REGISTER", "UNDO"}

    
    def execute(self, context):

        fluid_mesh = get_common_vars(context, get_fluid_mesh=True)
        all_brusheable_items = fluid_mesh.get_all_dp_brusheable
        
        for item in all_brusheable_items:
            
            ob = item.ob
            set_active_object(context, ob)
            
            canvas_mod = ob.modifiers.get(FluidLabNaming.DP_CANVAS_MOD)
            if not canvas_mod:
                canvas_mod = create_modifier(ob, FluidLabNaming.DP_CANVAS_MOD, 'DYNAMIC_PAINT')

            canvas_mod.ui_type = 'BRUSH'
            
            if not isinstance(canvas_mod.canvas_settings, DynamicPaintCanvasSettings):
                bpy.ops.dpaint.type_toggle(type='BRUSH')

            # if isinstance(canvas_mod.canvas_settings, DynamicPaintCanvasSettings):

            item.dp_without_brush = False # para q no salga azul la papelera, tuve que invertir el concepto a false

        return {'FINISHED'}



class FLUIDLAB_OT_dynamic_paint_add_canvas(Operator):
    bl_idname = "fluidlab.dynamic_paint_add_canvas"
    bl_label = "Add Canvas"
    bl_description = "Add Canvas"
    bl_options = {"REGISTER", "UNDO"}


    def add_vertex_group(self, ob: Object) -> VertexGroup:
        vg = ob.vertex_groups.get(FluidLabNaming.ACT_VG_DP_WEIGHT)
        if not vg:
            vg = ob.vertex_groups.new(name=FluidLabNaming.ACT_VG_DP_WEIGHT)
    
        vg.add(range(len(ob.data.vertices)), 1.0, 'ADD')
        return vg


    def execute(self, context):

        fluid_single_colliders = get_common_vars(context, get_fluid_single_colliders=True)
        all_canvaseable_items = fluid_single_colliders.get_all_dp_canvaseable
        addon_preferences = FluidLabPreferences.get_prefs(context)

        # Agregamos y seteamos los vertex groups:

        for item in all_canvaseable_items:

            # Como ahora puede haber un solo item con multiples colliders:
            collider_ob = item.collider

            set_active_object(context, collider_ob)
            
            # Solo le agregamos canvas a los que no lo tengan ya:
            canvas_mod = collider_ob.modifiers.get(FluidLabNaming.DP_CANVAS_MOD)
            if canvas_mod:
                # Si ya tiene un canvas previo paso de el
                self.report({'INFO'}, f"{collider_ob.name} have alreade an canvas mod!, skip this object.")
                continue

            canvas_mod = create_modifier(collider_ob, FluidLabNaming.DP_CANVAS_MOD, 'DYNAMIC_PAINT')

            if not isinstance(canvas_mod.canvas_settings, DynamicPaintCanvasSettings):
                bpy.ops.dpaint.type_toggle(type='CANVAS')

            if isinstance(canvas_mod.canvas_settings, DynamicPaintCanvasSettings):
                canvas_surface = canvas_mod.canvas_settings.canvas_surfaces.active
                canvas_surface.surface_type = 'WEIGHT'
                vg = self.add_vertex_group(collider_ob)
                canvas_surface.output_name_a = vg.name
                point_cache = canvas_surface.point_cache
                point_cache.name = collider_ob.name
                canvas_surface.use_antialiasing = True

                canvas_surface.surface_format = 'IMAGE'
                canvas_surface.surface_type = 'PAINT'

                item.dp_without_canvas = False # para q no salga azul la papelera, tuve que invertir el concepto a false
                
                # Si está definido en el path de preferences un folder, entonces se lo autoseteo en la creación:
                dp_cache_path = addon_preferences.dp_cache_path
                if dp_cache_path:
                    canvas_surface.image_output_path = join(dp_cache_path, collider_ob.name)
                else:
                    if canvas_surface.image_output_path:
                        canvas_surface.image_output_path = join(canvas_surface.image_output_path, collider_ob.name)

        return {'FINISHED'}


class FLUIDLAB_OT_dynamic_paint_blur(Operator):
    bl_idname = "fluidlab.dynamic_paint_blur"
    bl_label = "Blur images"
    bl_description = "Blur images with pillow"
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):
        blur_image('/home/zebus3d/original_image.jpg', '/home/zebus3d/original_image_blured.jpg', 5)
        return {'FINISHED'}


class FLUIDLAB_OT_dynamic_paint_add_mat_img_sequence(Operator):
    bl_idname = "fluidlab.dynamic_add_mat_img_sequence"
    bl_label = "Add Material"
    bl_description = "Add to material Image sequence"
    bl_options = {"REGISTER", "UNDO"}


    def create_img_sequencer(self, nodes, x, y, selected:bool=False):
        image_sequencer = nodes.new(type='ShaderNodeTexImage')
        image_sequencer.location = (x, y)
        image_sequencer.select = selected
        return image_sequencer
    

    def get_full_path(self, surface) -> Union[str, None]:
        # print(f"Find files in {surface.image_output_path}...")                
        files = listdir(surface.image_output_path)
        extension = surface.image_fileformat.lower()
        filtered_files = [file for file in files if file.startswith(surface.output_name_a) and file.lower().endswith(extension)]
        if filtered_files:
            filtered_files.sort()
            # print(f"Sequence: {filtered_files}")
            first_file = filtered_files[0]
            full_path = join(surface.image_output_path, first_file)

            return full_path


    def execute(self, context):
        
        # TODO: Falta por hacer el resto de situaciones.
        
        fluid_colliders = get_common_vars(context, get_fluid_colliders=True)
        all_items_colliders = fluid_colliders.get_all_items

        for collider_item in all_items_colliders:

            # Ahora los colliders pueden ser varios:
            colliders_obs = [c_ob.ob for c_ob in collider_item.colliders]
            for collider_ob in colliders_obs:

                # Si no tiene materials slots:
                if len(collider_ob.material_slots) <1:

                    mat = bpy.data.materials.new(name="NuevoMaterial")
                    collider_ob.data.materials.append(mat)
                    collider_ob.active_material = mat

                    mat.use_nodes = True
                    nodes = mat.node_tree.nodes
                    principled_bsdf = nodes.get("Principled BSDF")
                    principled_bsdf.select = False

                    if principled_bsdf is not None:

                        image_sequencer = self.create_img_sequencer(nodes, principled_bsdf.location.x-300, principled_bsdf.location.y)

                        md = collider_ob.modifiers.get(FluidLabNaming.DP_CANVAS_MOD)
                        if md:

                            canvas = md.canvas_settings
                            surface = canvas.canvas_surfaces.active

                            # set image sequence:

                            full_path = self.get_full_path(surface)
                            if full_path:
                                image_sequencer.image = bpy.data.images.load(full_path)

                                image_sequencer.image.source = 'SEQUENCE'
                                image_sequencer.image_user.use_auto_refresh = True

                            # link image sequence to principled:
                            mat.node_tree.links.new(image_sequencer.outputs["Color"], principled_bsdf.inputs["Base Color"])

        return {'FINISHED'}